Imports Microsoft.DirectX.Direct3D.Geometry

''' <summary>
'''     The Camera class provides an easy way to manipulate the View and Projection matricies of a 'Direct3D.Device' object.
''' </summary>
''' <remarks>
'''     The Camera class uses a 'Matrix.PerspectiveFovLH' perspective matrix by default.     
'''     <p>The camera is created with the fallowing default values ...</p>
''' <example>
''' <code>
'''     ViewMatrix                      Matrix.Identity
'''     ProjectionMatrix                Matrix.Identity
'''     Position                        Vector3(0, 0, -100)
'''     LookAt                          Vector3(0, 0, 0)
'''     Orientation                     Vector3(0, 1, 0)
'''     FieldOfView                     90 degrees 'Direct3D.Geometry.DegreeToRadian(90)'
'''     AspectRation                    1
'''     NearPlane                       1
'''     FarPlane                        1000
'''     ProjectionRectangle             0, 0, 640, 480
'''     CameraType                      Camera3D
''' </code>
''' </example>
''' </remarks>
Public Class Camera
    Implements IDisposable, ICloneable

    Protected Friend mobjDX9 As Direct3D.Device
    Protected Friend mtypView, mtypProj As Matrix
    Protected Friend mtypPosition, mtypLookAt, mtypOrientation As Vector3
    Protected Friend msngFOV, msngAspectRatio, msngNearPlane, msngFarPlane As Single
    Protected Friend mblnAutoUpdateView As Boolean = True
    Protected Friend mblnAutoUpdateProjection As Boolean = True
    Protected Friend mblnViewWorldLock As Boolean = False
    Protected Friend mintCamType As CameraType = CameraType.Camera2D
    Protected Friend mobjProjectionRectangle As RectangleF


    Public Overridable Sub VStrafe(ByVal Distance As Single)
        Dim vStrafe As Vector3 = mtypOrientation
        vStrafe.Multiply(Distance)
        mtypPosition.Add(vStrafe)
        mtypLookAt.Add(vStrafe)
    End Sub

    Public Overridable Sub HStrafe(ByVal Distance As Single)
        Dim vStrafe As Vector3 = Vector3.Cross(Vector3.Subtract(Me.LookAt, Me.Position), Me.Orientation)
        vStrafe.Multiply(Distance)
        mtypPosition.Add(vStrafe)
        mtypLookAt.Add(vStrafe)
    End Sub

    ''' <summary>
    ''' Gets/Sets the style of projection matrix to use.
    ''' </summary>
    ''' <returns>Returns the style of projection matrix the camera uses.</returns>
    Public Property CameraType() As CameraType
        Get
            Return mintCamType
        End Get
        Set(ByVal Value As CameraType)
            mintCamType = Value
        End Set
    End Property

    Public Overridable Function GetRotation() As Vector3
        Dim V As Vector3

        V.X = GetRotation(Alpha3D.Orientation.XY)
        V.Y = GetRotation(Alpha3D.Orientation.XZ)
        V.Z = GetRotation(Alpha3D.Orientation.XY)
        Return V
    End Function

    Public Overridable Function GetRotation(ByVal Axis As Orientation) As Single
        Return MathHelpers.GetRotation(Axis, mtypPosition, mtypLookAt)
    End Function


#Region " Rotate overloads ... "
    Public Sub Rotate(ByVal X As Integer, Optional ByVal AsRadian As Boolean = True)
        Me.Rotate(X, 0, 0, AsRadian)
    End Sub

    Public Sub Rotate(ByVal X As Integer, ByVal Y As Integer, Optional ByVal AsRadian As Boolean = True)
        Me.Rotate(X, Y, 0, AsRadian)
    End Sub

    Public Sub Rotate(ByVal X As Integer, ByVal Y As Integer, ByVal Z As Integer, Optional ByVal AsRadian As Boolean = True)
        If AsRadian Then
            Me.Rotate(New Vector3(X, Y, Z))
        Else
            Me.Rotate(New Vector3(DegreeToRadian(X), DegreeToRadian(Y), DegreeToRadian(Z)))
        End If
    End Sub

    Public Sub Rotate(ByVal X As Single, Optional ByVal AsRadian As Boolean = True)
        Me.Rotate(X, 0, 0, AsRadian)
    End Sub

    Public Sub Rotate(ByVal X As Single, ByVal Y As Single, Optional ByVal AsRadian As Boolean = True)
        Me.Rotate(X, Y, 0, AsRadian)
    End Sub

    Public Sub Rotate(ByVal X As Single, ByVal Y As Single, ByVal Z As Single, Optional ByVal AsRadian As Boolean = True)
        If AsRadian Then
            Me.Rotate(New Vector3(X, Y, Z))
        Else
            Me.Rotate(New Vector3(DegreeToRadian(X), DegreeToRadian(Y), DegreeToRadian(Z)))
        End If
    End Sub

    Public Sub Rotate(ByVal Yaw As Single, ByVal Pitch As Single, ByVal Roll As Single, ByVal Distance As Single)
        mtypLookAt = Vector3.Add(mtypPosition, New Vector3(0, 0, Distance))
        mtypLookAt = MathHelpers.RotateAroundAxis(mtypPosition, mtypLookAt, New Vector3(Yaw, Pitch, Roll))
        If mblnAutoUpdateView Then Me.UpdateView()
    End Sub

    Public Sub Rotate(ByVal Yaw As Integer, ByVal Pitch As Integer, ByVal Roll As Integer, ByVal Distance As Single)
        mtypLookAt = Vector3.Add(mtypPosition, New Vector3(0, 0, Distance))
        mtypLookAt = MathHelpers.RotateAroundAxis(mtypPosition, mtypLookAt, New Vector3(DegreeToRadian(Yaw), DegreeToRadian(Pitch), DegreeToRadian(Roll)))
        If mblnAutoUpdateView Then Me.UpdateView()
    End Sub

    Public Sub Rotate(ByVal Rotation As Vector3)
        ' rotate the look at position around the cameras position.
        mtypLookAt = MathHelpers.RotateAroundAxis(mtypPosition, mtypLookAt, Rotation)
        ' update the view projection
        If mblnAutoUpdateView Then Me.UpdateView()
    End Sub
#End Region



#Region " Constructor overloads ... "
    ''' <summary>
    '''     Creates a new instance of this class.
    ''' </summary>
    Public Sub New()
        MyBase.new()
        Reset()
    End Sub

    ''' <summary>
    '''     Initilizes the camera using a 'DX9Graphics' reference.
    ''' </summary>
    ''' <param name="Graphics" type="CBX.Libs.DX9Tools.DX9Graphics">Reference to a DX9Graphics object.</param>
    ''' <remarks>
    ''' <p>The camera class will use the 'Device' property of the DX9Graphics object that
    ''' you pass and store it's reference internally.</p>
    ''' 
    ''' <p>The reference to the Direct3D.Device is nessary because if, for example, you set
    ''' the FieldOfView property and the AutoUpdateProjection property is True a call to
    ''' the UpdateProjection method is made automatically.</p>
    ''' 
    ''' <p>The UpdateProjection method uses the reference to the device to update the devices Projection transform.</p>
    ''' </remarks>   
    ''' <exception cref="ArgumentNullException">
    '''     Will throw a ArgumentNullException Exception if the Graphics parameter is nothing.
    ''' </exception>
    ''' <exception cref="ArgumentNullException">
    '''     Will throw a ArgumentNullException Exception if the Graphics.Device property is nothing.
    ''' </exception>
    Public Sub New(ByVal Graphics As MyDevice)
        MyBase.new()
        If Graphics Is Nothing Then Throw New System.ArgumentNullException("Graphics")
        If Graphics.Device Is Nothing Then Throw New System.ArgumentNullException("Graphics.Device")
        'SetDeviceReference(Graphics.Device)
        mobjDX9 = Graphics.Device
        Reset()
    End Sub

    ''' <summary>
    '''     Initilizes the camera using a 'Direct3D.Device' reference.
    ''' </summary>
    ''' <param name="Device" type="Microsoft.DirectX.Direct3D.Device">Reference to a Direct3D.Device object.</param>
    ''' <remarks>
    ''' <p>The reference to the Direct3D.Device is nessary because if, for example, you set
    ''' the FieldOfView property and the AutoUpdateProjection property is True a call to
    ''' the UpdateProjection method is made automatically.</p>
    ''' 
    ''' <p>The UpdateProjection method uses the reference to the device to update it's Projection transform.</p>
    ''' </remarks>
    ''' <exception cref="ArgumentNullException">
    '''     Will throw a ArgumentNullException Exception if the Device parameter is nothing.
    ''' </exception>
    Public Sub New(ByVal Device As Device)
        MyBase.new()
        If Device Is Nothing Then Throw New System.ArgumentNullException("Device")
        'SetDeviceReference(Device)
        mobjDX9 = Device
        Reset()
    End Sub
#End Region



    ''' <summary>
    '''     Resets the camera to it's default values.
    ''' </summary>
    ''' <param name="DoUpdate" type="Boolean">
    '''         If DoUpdate is False but the AutoUpdateView property is True, Reset will call the UpdateView method.
    '''         If DoUpdate is False but the AutoUpdateProjection property is True, Reset will call the UpdateProjection method.
    ''' </param>
    ''' <remarks>
    ''' <p>If either the AutoUpdateView or the DoUpdate parameter is true a call to the UpdateView method is done automatically.</p>
    ''' <p>If either the AutoUpdateProjection or the DoUpdate parameter is true a call to the UpdateProjection method is done automatically.</p>
    ''' 
    '''     <p>Reset sets the camera to the fallowing default values ...</p>
    ''' <example>
    ''' <code>
    '''     ViewMatrix                      Matrix.Identity
    '''     ProjectionMatrix                Matrix.Identity
    '''     Position                        Vector3(0, 0, -100)
    '''     LookAt                          Vector3(0, 0, 0)
    '''     Orientation                     Vector3(0, 1, 0)
    '''     FieldOfView                     90 degrees 'Direct3D.Geometry.DegreeToRadian(90)'
    '''     AspectRation                    1
    '''     NearPlane                       1
    '''     FarPlane                        1000
    '''     ProjectionRectangle             0, 0, 640, 480
    '''     CameraType                      Camera3D
    ''' </code>
    ''' </example>
    ''' </remarks>
    Public Overridable Sub Reset(Optional ByVal DoUpdate As Boolean = False)
        mtypView = Matrix.Identity
        mtypProj = Matrix.Identity
        mintCamType = CameraType.Camera3D
        mobjProjectionRectangle = New RectangleF(0, 0, 640, 480)
        mtypPosition = New Vector3(0, 0, -100)
        mtypLookAt = New Vector3(0, 0, 0)
        mtypOrientation = New Vector3(0, 1, 0)
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()

        msngFOV = Direct3D.Geometry.DegreeToRadian(90)
        msngAspectRatio = 1.0
        msngNearPlane = 1.0
        msngFarPlane = 1000.0
        If mblnAutoUpdateProjection Or DoUpdate Then UpdateProjection()
    End Sub

    ''' <summary>
    '''     Returns a reference to a private view matrix.
    ''' </summary>
    ''' <remarks>
    '''     When working with this property be aware that it is not a direct reference to the 'Direct3D.Device.Transforms.View' matrix.
    '''     The camera class maintains it own view matrix.      
    ''' </remarks>
    Public Overridable Property View() As Matrix
        Get
            Return mtypView
        End Get
        Set(ByVal Value As Matrix)
            mtypView = Value
        End Set
    End Property

    ''' <summary>
    '''     Returns a reference to a private projection matrix not the 'Direct3D.Device.Transforms.Projection' matrix.
    ''' </summary>
    ''' <remarks>
    '''     When working with this property be aware that it is not a direct reference to the 'Direct3D.Device.Transforms.Projection' matrix.
    '''     The camera class maintains it own projection matrix.      
    ''' </remarks>
    Public Overridable Property Projection() As Matrix
        Get
            Return mtypProj
        End Get
        Set(ByVal Value As Matrix)
            mtypProj = Value
        End Set
    End Property

    ''' <summary>
    '''     Gets / Sets the cameras FOV or Field of view.
    ''' </summary>
    ''' <remarks>
    '''     If the AutoUpdateProjection property is True a call to the UpdateProjection is made automatically.
    ''' </remarks>
    Public Overridable Property FieldOfView() As Single
        Get
            Return msngFOV
        End Get
        Set(ByVal Value As Single)
            msngFOV = Value
            If mblnAutoUpdateProjection Then UpdateProjection()
        End Set
    End Property

    ''' <summary>
    '''     Gets / Sets the cameras aspect ratio.
    ''' </summary>
    ''' <remarks>
    '''     Typically if you were using a form to render your graphics, you would use the fallowing to calculate 
    '''     an acurate aspect ratio.
    ''' <example>
    ''' <code>
    '''     Camera.AspectRatio = Form.ClientSize.Width / Form.ClientSize.Height
    ''' </code>
    ''' </example>
    ''' </remarks>
    Public Overridable Property AspectRatio() As Single
        Get
            Return msngAspectRatio
        End Get
        Set(ByVal Value As Single)
            msngAspectRatio = Value
            If mblnAutoUpdateProjection Then UpdateProjection()
        End Set
    End Property

    ''' <summary>
    ''' Gets / Sets the value of the projection matrix's near viewing plane.
    ''' </summary>
    Public Overridable Property NearPlane() As Single
        Get
            Return msngNearPlane
        End Get
        Set(ByVal Value As Single)
            msngNearPlane = Value
            If mblnAutoUpdateProjection Then UpdateProjection()
        End Set
    End Property

    ''' <summary>
    ''' Gets / Sets the value of the projection matrix's far viewing plane.
    ''' </summary>
    Public Overridable Property FarPlane() As Single
        Get
            Return msngFarPlane
        End Get
        Set(ByVal Value As Single)
            msngFarPlane = Value
            If mblnAutoUpdateProjection Then UpdateProjection()
        End Set
    End Property

#Region " Position Methods ... "
    ''' <summary>
    ''' Gets / Sets the cameras Position.
    ''' </summary>
    ''' <returns>
    ''' Returns the cameras Position as a 'DirectX.Vector3' type.
    ''' </returns>
    ''' <remarks>
    ''' <p>The Position property represents the point in 3D space that the camera is positioned at.</p>
    ''' 
    ''' <p>The Camera class stores a private DirectX.Vector3 varible for storing the cameras Position.</p>
    ''' 
    ''' <p>If the AutoUpdateView property is True a call to the UpdateView method is made automatically.</p>
    ''' </remarks>
    Public Overridable Property Position() As Vector3
        Get
            Return mtypPosition
        End Get
        Set(ByVal Value As Vector3)
            mtypPosition = Value
            If mblnAutoUpdateView Then UpdateView()
        End Set
    End Property

    ''' <overloads>
    ''' The camera class has four SetPosition method overloads.
    ''' </overloads>
    ''' <summary>
    '''     Sets the position of the camera.
    ''' </summary>
    ''' <param name="What" type="CBX.Libs.DX9Tools.Camera.SetVector">Defines what specific part(s) of the Vector3 type will be set to the Value parameter.</param>
    ''' <param name="Value" type="Single">The value that will be passed into the Cameras private Vector3 varible.</param>
    ''' <param name="DoUpdate" type="Boolean">If DoUpdate is False but the AutoUpdateView property is True, SetPosition will call the UpdateView method.</param>
    ''' <remarks>
    '''     You can specify multiple parts of a vector to set, for example ...
    ''' <example>
    ''' <code>
    '''     Camera.SetPosition(SetVector.X or SetVector.Z, 12, False)
    ''' </code>
    ''' </example>
    ''' Both the X and Z parts of the Vector3 type that the Camera class privately stores will be set to 12.
    ''' </remarks>
    Public Sub SetPosition(ByVal What As SetVector, ByVal Value As Single, Optional ByVal DoUpdate As Boolean = False)
        If CBool(What And SetVector.X) Then mtypPosition.X = Value
        If CBool(What And SetVector.Y) Then mtypPosition.Y = Value
        If CBool(What And SetVector.Z) Then mtypPosition.Z = Value
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    '''     Sets the position of the camera.
    ''' </summary>
    ''' <param name="X" type="Single">Parameter name is self explanitory.</param>
    ''' <param name="DoUpdate" type="Boolean">If DoUpdate is False but the AutoUpdateView property is True, SetPosition will call the UpdateView method.</param>
    Public Sub SetPosition(ByVal X As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypPosition.X = X
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    '''     Sets the position of the camera.
    ''' </summary>
    ''' <param name="X" type="Single">Parameter name is self explanitory.</param>
    ''' <param name="Y" type="Single">Parameter name is self explanitory.</param>
    ''' <param name="DoUpdate" type="Boolean">If DoUpdate is False but the AutoUpdateView property is True, SetPosition will call the UpdateView method.</param>
    Public Sub SetPosition(ByVal X As Single, ByVal Y As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypPosition.X = X
        mtypPosition.Y = Y
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    '''     Sets the position of the camera.
    ''' </summary>
    ''' <param name="X" type="Single">Parameter name is self explanitory.</param>
    ''' <param name="Y" type="Single">Parameter name is self explanitory.</param>
    ''' <param name="Z" type="Single">Parameter name is self explanitory.</param>
    ''' <param name="DoUpdate" type="Boolean">If DoUpdate is False but the AutoUpdateView property is True, SetPosition will call the UpdateView method.</param>
    Public Sub SetPosition(ByVal X As Single, ByVal Y As Single, ByVal Z As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypPosition.X = X
        mtypPosition.Y = Y
        mtypPosition.Z = Z
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub
#End Region

#Region " LookAt methods ... "
    ''' <summary>
    ''' Gets / Sets the cameras LookAt position.
    ''' </summary>
    ''' <returns>
    ''' Returns the cameras LookAt position as a 'DirectX.Vector3' type.
    ''' </returns>
    ''' <remarks>
    ''' <p>The LookAt position property represents the point in 3D space that the camera is looking at.</p>
    '''  
    ''' <p>The Camera class stores a private DirectX.Vector3 varible for storing the cameras LookAt position.</p>
    ''' 
    ''' <p>If the AutoUpdateView property is True a call to the UpdateView method is made automatically.</p>
    ''' </remarks>
    Public Overridable Property LookAt() As Vector3
        Get
            Return mtypLookAt
        End Get
        Set(ByVal Value As Vector3)
            mtypLookAt = Value
            If mblnAutoUpdateView Then UpdateView()
        End Set
    End Property

    ''' <summary>
    ''' Gets / Sets the point that the camera is looking at.
    ''' </summary>
    ''' <param name="What">Used to determin what axis(s) to set.</param>
    ''' <param name="Value">The value to set the orientation to.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetLookAt(ByVal What As SetVector, ByVal Value As Single, Optional ByVal DoUpdate As Boolean = False)
        If CBool(What And SetVector.X) Then mtypLookAt.X = Value
        If CBool(What And SetVector.Y) Then mtypLookAt.Y = Value
        If CBool(What And SetVector.Z) Then mtypLookAt.Z = Value
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    ''' Sets the LookAt position for the camera.
    ''' </summary>
    ''' <param name="X">The value of the X axis to set.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetLookAt(ByVal X As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypLookAt.X = X
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    ''' Sets the LookAt position for the camera.
    ''' </summary>
    ''' <param name="X">The value of the X axis to set.</param>
    ''' <param name="Y">The value of the Y axis to set.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetLookAt(ByVal X As Single, ByVal Y As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypLookAt.X = X
        mtypLookAt.Y = Y
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    ''' Sets the LookAt position for the camera.
    ''' </summary>
    ''' <param name="X">The value of the X axis to set.</param>
    ''' <param name="Y">The value of the Y axis to set.</param>
    ''' <param name="Z">The value of the Z axis to set.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetLookAt(ByVal X As Single, ByVal Y As Single, ByVal Z As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypLookAt.X = X
        mtypLookAt.Y = Y
        mtypLookAt.Z = Z
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub
#End Region

#Region " Orientation methods ... "
    ''' <summary>
    ''' Gets / Sets the cameras Orientation.
    ''' </summary>
    ''' <returns>
    ''' Returns the cameras orientation as a 'DirectX.Vector3' type.
    ''' </returns>
    ''' <remarks>
    ''' <p>The Orientation property represents a direction in 3D space that the camera is oriented towards.</p>
    ''' 
    ''' <p>The Camera class stores a private DirectX.Vector3 varible for storing the cameras orientation.</p>
    ''' 
    ''' <p>If the AutoUpdateView property is True a call to the UpdateView method is made automatically.</p>
    ''' </remarks>
    Public Overridable Property Orientation() As Vector3
        Get
            Return mtypOrientation
        End Get
        Set(ByVal Value As Vector3)
            mtypOrientation = Value
            If mblnAutoUpdateView Then UpdateView()
        End Set
    End Property

    ''' <summary>
    ''' Sets the orientation for the camera.
    ''' </summary>
    ''' <param name="What">Used to determin what axis(s) to set.</param>
    ''' <param name="Value">The value to set the orientation to.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetOrientation(ByVal What As SetVector, ByVal Value As Single, Optional ByVal DoUpdate As Boolean = False)
        If CBool(What And SetVector.X) Then mtypOrientation.X = Value
        If CBool(What And SetVector.Y) Then mtypOrientation.Y = Value
        If CBool(What And SetVector.Z) Then mtypOrientation.Z = Value
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    ''' Sets the orientation for the camera.
    ''' </summary>
    ''' <param name="X">The value of the X axis to set.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetOrientation(ByVal X As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypOrientation.X = X
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    ''' Sets the orientation for the camera.
    ''' </summary>
    ''' <param name="X">The value of the X axis to set.</param>
    ''' <param name="Y">The value of the Y axis to set.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetOrientation(ByVal X As Single, ByVal Y As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypOrientation.X = X
        mtypOrientation.Y = Y
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub

    ''' <summary>
    ''' Sets the orientation for the camera.
    ''' </summary>
    ''' <param name="X">The value of the X axis to set.</param>
    ''' <param name="Y">The value of the Y axis to set.</param>
    ''' <param name="Z">The value of the Z axis to set.</param>
    ''' <param name="DoUpdate">If True, a call to the UpdateView method is made.</param>
    Public Sub SetOrientation(ByVal X As Single, ByVal Y As Single, ByVal Z As Single, Optional ByVal DoUpdate As Boolean = False)
        mtypOrientation.X = X
        mtypOrientation.Y = Y
        mtypOrientation.Z = Z
        If mblnAutoUpdateView Or DoUpdate Then UpdateView()
    End Sub
#End Region

    ''' <summary>
    ''' Builds a private matrix varible stored inside of the camera object, then sets the internal
    ''' Direct3D.Device references view transform to that private matrix varible.
    ''' </summary>
    Public Overridable Sub UpdateView()
        mtypView = Matrix.LookAtLH(mtypPosition, mtypLookAt, mtypOrientation)
        If mblnViewWorldLock Then
            ' mobjDX9.SetTransform(Direct3D.TransformType.View, mtypView)
            mobjDX9.SetTransform(Direct3D.TransformType.World, mtypView)
        Else
            mobjDX9.SetTransform(Direct3D.TransformType.View, mtypView)
        End If
    End Sub

    ''' <summary>
    ''' Builds a private matrix varible stored inside of the camera object, then sets the internal
    ''' Direct3D.Device references projection transform to that private matrix varible.
    ''' </summary>
    Public Overridable Sub UpdateProjection()
        Select Case mintCamType
            Case CameraType.Camera2D
                Me.mtypProj = Matrix.OrthoOffCenterLH(mobjProjectionRectangle.Left, mobjProjectionRectangle.Right, _
                                                      mobjProjectionRectangle.Bottom, mobjProjectionRectangle.Top, _
                                                      msngNearPlane, msngFarPlane)
            Case CameraType.Camera3D
                Me.mtypProj = Matrix.PerspectiveFovLH(msngFOV, msngAspectRatio, msngNearPlane, msngFarPlane)
        End Select

        mobjDX9.SetTransform(Direct3D.TransformType.Projection, mtypProj)
    End Sub

    ''' <summary>
    ''' Use this method instead of calling the UpdateView and UpdateProjection methods separately.
    ''' </summary>                              
    Public Overridable Sub UpdateVP()
        Me.UpdateView()
        Me.UpdateProjection()
    End Sub

    ''' <summary>
    ''' Cleans up and disposes of the camera's internal varibles and references.
    ''' </summary>
    Protected Overrides Sub Finalize()
        MyBase.Finalize()
        Me.Dispose()
        'mobjParent = Nothing
    End Sub

    ''' <summary>
    ''' If set to True, Methods like SetPosition will automatically call the UpdateView method.
    ''' </summary>
    ''' <returns>
    ''' Return the current True / False state.
    ''' </returns>
    Public Overridable Property AutoUpdateView() As Boolean
        Get
            Return mblnAutoUpdateView
        End Get
        Set(ByVal Value As Boolean)
            mblnAutoUpdateView = Value
        End Set
    End Property

    ''' <summary>
    ''' If set to True, Properties like FieldOfView will automatically call the UpdateProjecttion method.
    ''' </summary>
    ''' <returns>
    ''' Return the current True / False state.
    ''' </returns>
    Public Overridable Property AutoUpdateProjection() As Boolean
        Get
            Return mblnAutoUpdateProjection
        End Get
        Set(ByVal Value As Boolean)
            mblnAutoUpdateProjection = Value
        End Set
    End Property

    ''' <summary>
    ''' Gets/Sets the Direct3D.Device that the camera will work with.
    ''' </summary>
    ''' <returns>Returns the Direct3D.Device that the camera is working with.</returns>
    Public Overridable Property Device() As Device
        Get
            Return mobjDX9
        End Get
        Set(ByVal Value As Direct3D.Device)
            mobjDX9 = Value
        End Set
    End Property

    Public Overridable Sub Dispose() Implements System.IDisposable.Dispose
        Try
            ' If Not mobjDX9 Is Nothing Then mobjDX9.Dispose()
            mobjDX9 = Nothing
        Catch ex As Exception
            'ERR: handle error?
        End Try
    End Sub

    Public Property ProjectionRectangle() As RectangleF
        Get
            Return mobjProjectionRectangle
        End Get
        Set(ByVal Value As RectangleF)
            mobjProjectionRectangle = Value
            If mblnAutoUpdateProjection Then UpdateProjection()
        End Set
    End Property

    Public Property ViewWorldLock() As Boolean
        Get
            Return mblnViewWorldLock
        End Get
        Set(ByVal Value As Boolean)
            mblnViewWorldLock = Value
        End Set
    End Property

    Public Function Clone() As Object Implements System.ICloneable.Clone
        Dim Cam As New Camera

        Cam.mobjDX9 = mobjDX9
        Cam.mtypView = mtypView
        Cam.mtypProj = mtypProj
        Cam.mtypPosition = mtypPosition
        Cam.mtypLookAt = mtypLookAt
        Cam.mtypOrientation = mtypOrientation
        Cam.msngFOV = msngFOV
        Cam.msngAspectRatio = msngAspectRatio
        Cam.msngNearPlane = msngNearPlane
        Cam.msngFarPlane = msngFarPlane
        Cam.mblnAutoUpdateView = mblnAutoUpdateView
        Cam.mblnAutoUpdateProjection = mblnAutoUpdateProjection
        Cam.mblnViewWorldLock = mblnViewWorldLock
        Cam.mintCamType = mintCamType
        Cam.mobjProjectionRectangle = mobjProjectionRectangle

        Return Cam
    End Function
End Class